from rest_framework import serializers
from . import models
from course.models import Course
from rest_framework.exceptions import ValidationError
from django.conf import settings
class PaySerializer(serializers.ModelSerializer):
    # 要支持单购物和群购物（购物车）,前台要提交课程主键(们)
    courses = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(),write_only=True,many=True)
    class Meta:
        model = models.Order
        fields = ['subject','total_amount','pay_type','courses']
        extra_kwargs = {
            'total_amount' : {
                'required' : True
            },
            'pay_type': {
                'required': True
            }
        }

    # 订单总价校验
    def _check_total_amount(self,attrs):
        courses = attrs.get('courses')
        total_amount = attrs.get('total_amount')
        total_price = 0
        for course in courses:
            total_price += course.price
        if total_price != total_amount:
            raise ValidationError('total_amount error')
        return total_amount

    # 生成订单号
    def _get_out_trade_no(self):
        import uuid
        code = '%s' % uuid.uuid4()
        return code.replace('-','')

    # 获取支付人
    def _get_user(self):
        print(self.context.get('request').user)
        return self.context.get('request').user

    # 获取支付链接
    def _get_pay_url(self,out_trade_no,total_amount,subject):
        from libs import iPay
        order_string = iPay.alipay.api_alipay_trade_page_pay(
            out_trade_no=out_trade_no,  # 后台服务器在创建订单表时生成地订单号
            total_amount=float(total_amount),  # 只有生成支付宝链接时，不能用Decimal
            subject=subject,  # 前台提交给后台的商品名
            return_url=settings.RETURN_URL,  # 在项目settings中配置前台get同步回调接口，必须是公网地址（本地也可以测试）
            notify_url=settings.NOTIFY_URL  # 在项目settings中配置后台post8次异步回调接口，必须是公网地址
        )
        pay_url = iPay.gateway + '?' + order_string
        # 将支付链接存入context，传给视图层
        self.context['pay_url'] = pay_url

    # 入库（两个表)的信息准备
    def _before_create(self,attrs,user,out_trade_no):
        attrs['user'] = user
        attrs['out_trade_no'] = out_trade_no

    def validate(self,attrs):
        # 1) 订单总价校验
        total_amount = self._check_total_amount(attrs)
        # 2）生成订单号
        out_trade_no = self._get_out_trade_no()
        # 3）支付用户：request.user
        user = self._get_user()
        # 4) 支付链接生成
        self._get_pay_url(out_trade_no,total_amount,attrs.get('subject'))
        # 5) 入库（两个表)的信息准备
        self._before_create(attrs,user,out_trade_no)

        # 代表该校验方法通过，进入入库操作
        return attrs

    # 重写入库方法的目的，完成订单与订单详情两个表入库操作
    def create(self,validated_data):
        courses = validated_data.pop('courses')
        # 订单表入库，不需要courses
        order = models.Order.objects.create(**validated_data)
        # 订单详情表入库，只需要订单对象，课程对象(courses要拆成course)
        for course in courses:
            models.OrderDetail.objects.create(order=order,course=course,price=course.price,real_price=course.price)
        # 先循环制造数据列表，用群增完成入库bulk_create(),效率高
        return order